package org.apache.shardingsphere.elasticjob.lite.ui.service.impl;

import org.apache.shardingsphere.elasticjob.lite.ui.domain.*;
import org.apache.shardingsphere.elasticjob.lite.ui.repository.ConfigurationsXmlRepository;
import org.apache.shardingsphere.elasticjob.lite.ui.repository.impl.ConfigurationsXmlRepositoryImpl;
import org.apache.shardingsphere.elasticjob.lite.ui.service.UserManageService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description user manage Operations service class
 * @Author JL
 */
@Service
public class UserManageServiceImpl implements UserManageService {

    private ConfigurationsXmlRepository configurationsXmlRepository = new ConfigurationsXmlRepositoryImpl();
    private final static String STATUS_OK="OK";
    private final static String STATUS_DISABLED="DISABLED";

    /**
     * user login validate
     * @param account
     * @param password
     * @return
     */
    @Override
    public boolean loginValidate(final String account, final String password){
        UserManage result = load(account);
        if (null != result && STATUS_OK.equals(result.getStatus())){
            if (result.getAccount().equals(account) && result.getPassword().equals(password)){
                return true;
            }
        }
        return false;
    }

    /**
     * search account user
     * @return
     */
    @Override
    public UserManages search(final String account) {
        UserManages userManages = loadGlobal().getUserManages();
        userManages.setUserManage(userManages.
                getUserManage().
                stream().
                filter(toBeUserManage->toBeUserManage.getAccount().indexOf(account) != -1).
                collect(Collectors.toSet()));
        return userManages;
    }

    /**
     * load all user
     * @return
     */
    @Override
    public UserManages loadAll() {
        return loadGlobal().getUserManages();
    }

    /**
     * load login user
     * @param account
     * @return
     */
    @Override
    public UserManage load(final String account) {
        GlobalConfiguration configs = loadGlobal();
        return find(account, configs.getUserManages());
    }

    /**
     * find login user
     * @param account
     * @param configs
     * @return
     */
    @Override
    public UserManage find(final String account, final UserManages configs) {
        for (UserManage each : configs.getUserManage()) {
            if (account.equals(each.getAccount())) {
                return each;
            }
        }
        return null;
    }

    /**
     * enable user
     * @param account
     * @return
     */
    @Override
    public boolean enable(final String account){
        setStatus(account, STATUS_OK);
        return true;
    }

    /**
     * disable user
     * @param account
     * @return
     */
    @Override
    public boolean disable(final String account){
        setStatus(account, STATUS_DISABLED);
        return true;
    }

    /**
     * devolve config from user A to user B
     * @param fromAccount
     * @param toAccount
     * @return
     */
    @Override
    public boolean devolve(final String fromAccount, final String toAccount){
        GlobalConfiguration result = configurationsXmlRepository.load();
        EventTraceDataSourceConfigurations dataSources = result.getEventTraceDataSourceConfigurations();
        RegistryCenterConfigurations configs = result.getRegistryCenterConfigurations();
        Set<EventTraceDataSourceConfiguration> eventDataSources = dataSources.getEventTraceDataSourceConfiguration().stream().map(dataSource->{
            if (fromAccount.equals(dataSource.getAccount())){
                dataSource.setAccount(toAccount);
            }
            return dataSource;
        }).collect(Collectors.toSet());
        dataSources.setEventTraceDataSourceConfiguration(eventDataSources);
        Set<RegistryCenterConfiguration> regConfigs = configs.getRegistryCenterConfiguration().stream().map(config->{
            if (fromAccount.equals(config.getAccount())){
                config.setAccount(toAccount);
            }
            return config;
        }).collect(Collectors.toSet());
        configs.setRegistryCenterConfiguration(regConfigs);
        configurationsXmlRepository.save(result);
        return true;
    }

    /**
     * set account to user status
     * @param account
     * @param status
     */
    private void setStatus(final String account, final String status){
        GlobalConfiguration configs = loadGlobal();
        UserManage toBeUserManage = findGlobalConfigurationUser(account, configs);
        if (null != toBeUserManage && !status.equals(toBeUserManage.getStatus())) {
            toBeUserManage.setStatus(status);
            configurationsXmlRepository.save(configs);
        }
    }

    /**
     *  from configs find by account his user info
     * @param account
     * @param configs
     * @return
     */
    private UserManage findGlobalConfigurationUser(final String account, final GlobalConfiguration configs) {
        for (UserManage each : configs.getUserManages().getUserManage()) {
            if (account.equals(each.getAccount())) {
                return each;
            }
        }
        return null;
    }

    /**
     * save user
     * data save to xml (C:\Users\Administrator\.elasticjob-console\Configurations.xml)
     * @param userManage
     * @return
     */
    @Override
    public boolean save(final UserManage userManage) {
        GlobalConfiguration configs = loadGlobal();
        Set<UserManage> userManages = configs.getUserManages().getUserManage();
        boolean result = false;
        for (UserManage toBeUserManage : userManages){
            if (toBeUserManage.getAccount().equals(userManage.getAccount())){
                BeanUtils.copyProperties(userManage, toBeUserManage);
                result = true;
                break;
            }
        }
        if (!result){
            result = configs.getUserManages().getUserManage().add(userManage);
        }
        if (result) {
            configurationsXmlRepository.save(configs);
        }
        return result;
    }

    /**
     * delete by account to user
     * @param account
     */
    @Override
    public void delete(final String account) {
        GlobalConfiguration configs = loadGlobal();
        UserManage toBeRemovedUser = find(account, configs.getUserManages());
        if (null != toBeRemovedUser) {
            configs.getUserManages().getUserManage().remove(toBeRemovedUser);
            configurationsXmlRepository.save(configs);
        }
    }

    /**
     * load all config
     * @return
     */
    private GlobalConfiguration loadGlobal() {
        GlobalConfiguration result = configurationsXmlRepository.load();
        if (null == result.getUserManages()) {
            result.setUserManages(new UserManages());
        }
        return result;
    }
}
